/**
  ******************************************************************************
  * @file    /Gneiss.c
  * @author  Winbond FAE Steam Lin
  * @version V1.1.0
  * @date    09-December-2015
  * @brief   This code provide the low level RPMC hardware operate function based on STM32F205.
  *            
  * COPYRIGHT 2015 Winbond Electronics Corporation.
*/ 

#include "wblib.h"
#include "Gneiss.h"
#include "w55fa93_spi.h"

/* public array use for RPMC algorithm */
unsigned char message[16];	// Message data use for insturction input
unsigned char counter[4];	// counter data (32bit)
unsigned char tag[12];		// Tag data use for increase counter
unsigned char signature[32];	// Signature data use for every instruction output


INT32 RPMC_ReadJEDECID(PUINT8 data)
{

	outpw(REG_SPI0_SSR, inpw(REG_SPI0_SSR) | 0x01);	// CS0

	// command 8 bit
	outpw(REG_SPI0_TX0, 0x9F);
	spiTxLen(0, 0, 8);
	spiActive(0);

	// data 8 bit
	outpw(REG_SPI0_TX0, 0xff);
	spiTxLen(0, 0, 8);
	spiActive(0);
	*data++ = inpw(REG_SPI0_RX0) & 0xFF;

	// data 8 bit
	outpw(REG_SPI0_TX0, 0xff);
	spiTxLen(0, 0, 8);
	spiActive(0);
	*data++ = inpw(REG_SPI0_RX0) & 0xFF;
	
		// data 8 bit
	outpw(REG_SPI0_TX0, 0xff);
	spiTxLen(0, 0, 8);
	spiActive(0);
	*data++ = inpw(REG_SPI0_RX0) & 0xFF;

	outpw(REG_SPI0_SSR, inpw(REG_SPI0_SSR) & 0xfe);	// CS0

	return Successful;
}
INT16 RPMC_ReadUID(PUINT8 data)
{
	int i;
	outpw(REG_SPI0_SSR, inpw(REG_SPI0_SSR) | 0x01);	// CS0

	// command 8 bit
	outpw(REG_SPI0_TX0, 0x4B);
	spiTxLen(0, 0, 8);
	spiActive(0);

	// Dummy 32 bit
	outpw(REG_SPI0_TX0, 0x000000);
	spiTxLen(0, 0, 32);
	spiActive(0);

	for(i=0;i< 8;i++)
	{
		// data 8 bit
		outpw(REG_SPI0_TX0, 0xff);
		spiTxLen(0, 0, 8);
		spiActive(0);
		*data++ = inpw(REG_SPI0_RX0) & 0xFF;
	}
	
	outpw(REG_SPI0_SSR, inpw(REG_SPI0_SSR) & 0xfe);	// CS0

	return Successful;
}

/********************
Function: /CS goes low
Argument:
return:
date: 2015/8/12
*********************/
void CS_LOW(){
	outpw(REG_SPI0_SSR, inpw(REG_SPI0_SSR) | 0x01);	// CS0
}

/********************
Function: /CS goes high
Argument:
return:
date: 2015/8/12
*********************/
void CS_HIGH(){
	outpw(REG_SPI0_SSR, inpw(REG_SPI0_SSR) & 0xfe);	// CS0
}

/********************
Function: SPI Input/output
Argument: DI:
	SPI DI data
return:	SPI DO data
date: 2015/8/12
*********************/
unsigned char SPIin(unsigned char DI){
	unsigned char DO;
	outpw(REG_SPI0_TX0, DI);
	spiTxLen(0, 0, 8);
	spiActive(0);	
	DO = inpw(REG_SPI0_RX0) & 0xFF;		
	return DO;
}

/********************
Function: Read counter
Argument:
return:	counter number
date: 2015/8/12
*********************/
unsigned int RPMC_ReadCounterData(){
  return (((((counter[0]*0x100)+counter[1])*0x100)+counter[2])*0x100)+counter[3];
}

/********************
Function: RPMC read RPMC status
Argument: checkall

	checkall = 0: only read out RPMC status
	checkall = 1: Read out counter data, tag, signature information
	
return: RPMC status 
date: 2015/8/12
*********************/
unsigned int RPMC_ReadRPMCstatus(unsigned int checkall){
  unsigned int i;
  unsigned char RPMCstatus;
  CS_LOW();
  SPIin(0x96);		// read RPMC status command
  SPIin(0x00);
  RPMCstatus = SPIin(0x00);		// status was readout, read RPMC status don't need signature input
  if(checkall ==0)  {
    CS_HIGH();
  }
  else{							// After signature matched reqeust counter instruction, counter data can readout as follow.
    for(i=0;i<12;i++){
    tag[i]=SPIin(0x00);			// tag information repeat
    }
    for(i=0;i<4;i++){
    counter[i] = SPIin(0x00);	// counter data readout
    }
    for(i=0;i<32;i++){
    signature[i]=SPIin(0x00);	// signature repeat
    }
    CS_HIGH();
  }//end else
  return RPMCstatus;
}

/********************
Function: RPMC request counter data
Argument: 
	cadr: selected Counter address, from 1~4
	hmackey: 32 byte HMACKEY which is generated by RPMC_UpHMACkey()
	input_tag: 12 byte input Tag data, which can be time stamp, serial number or random number. 
	these data would repeat after success RPMC_ReqCounter() operation
return: 
date: 2015/8/12
*********************/
void RPMC_ReqCounter(unsigned int cadr, unsigned char *hmackey,unsigned char *input_tag){
  unsigned int i;
  message[0]=0x9B;
  message[1]=0x03;
  message[2]=cadr-1;
  message[3]=0x00;
  for(i=0;i<12;i++){
    message[i+4]=*(input_tag+i);
  }
  
  hmacsha256(hmackey,32,message,16,signature);  // caculate signature by SHA256
  
  CS_LOW();
  for(i=0;i<16;i++){
    SPIin(message[i]);
  }
  for(i=0;i<32;i++){
    SPIin(signature[i]);
  }
  CS_HIGH();
  return;
}

/********************
Function: RPMC write rootkey
Argument: 
	cadr: selected Counter address, from 1~4
	rootkey: 32 byte rootkey infomration.
return: RPMC status
date: 2015/8/12
*********************/
unsigned int RPMC_WrRootKey(unsigned int cadr,unsigned char *rootkey){
  unsigned int i;

  memset(message, 0x00, sizeof(message[0])*8);
  message[0]=0x9B;
  message[1]=0x00;
  message[2]=cadr-1;// counter address 0~3,so -1
  message[3]=0x00; 
  
  hmacsha256(rootkey,32,message,4,signature);	// caculate signature by SHA256
  
  CS_LOW();
  SPIin(message[0]);
  SPIin(message[1]);
  SPIin(message[2]);
  SPIin(message[3]);
  for(i=0;i<32;i++){
    SPIin(*(rootkey+i));
  }
  for(i=0;i<28;i++){
    SPIin(signature[i+4]);
  }
  CS_HIGH();
  
  while(RPMC_ReadRPMCstatus(0)&0x01==0x01){
	// wait until RPMC operation done
  }  
  return RPMC_ReadRPMCstatus(0);  
}

/********************
Function: RPMC Update HMAC key, this function should call in every Gneiss power on
Argument: 
	cadr: selected Counter address, from 1~4
	rootkey: rootkey use for generate HMAC key
	hmac4: 4 byte input hmac message data, which can be time stamp, serial number or random number. 
	hmackey: 32 byte HMACKEY, which would be use for increase/request counter after RPMC_UpHMACkey() operation success
return: 
date: 2015/8/12
*********************/
unsigned int RPMC_UpHMACkey(unsigned int cadr,unsigned char *rootkey,unsigned char *hmac4,unsigned char *hmackey){
  unsigned int i;
  
  message[0]=0x9B;
  message[1]=0x01;
  message[2]=cadr - 1;
  message[3]=0x00;
  message[4]=*(hmac4+0);
  message[5]=*(hmac4+1);
  message[6]=*(hmac4+2);
  message[7]=*(hmac4+3);
  
  hmacsha256(rootkey,32,hmac4,4,hmackey);	// use rootkey generate HMAC key by SHA256  
  hmacsha256(hmackey,32,message,8,signature);	// caculate signature by SHA256
  
  CS_LOW();
  for(i=0;i<8;i++){
  SPIin(message[i]);
  }
  for(i=0;i<32;i++){
  SPIin(signature[i]);
  }
  CS_HIGH();
  while(RPMC_ReadRPMCstatus(0)&0x01==0x01){
	// wait until RPMC operation done
  }  
  return RPMC_ReadRPMCstatus(0); 
}

/********************
Function: RPMC request counter data
Argument: 
	cadr: selected Counter address, from 1~4
	hmackey: 32 byte HMACKEY which is generated by RPMC_UpHMACkey()
	input_tag: 12 byte input Tag data, which can be time stamp, serial number or random number. 
	these data would repeat after success RPMC_ReqCounter() operation
return: 
date: 2015/8/12
*********************/
unsigned int RPMC_IncCounter(unsigned int cadr,unsigned char *hmackey,unsigned char *input_tag){
  unsigned int i;
  
  RPMC_ReqCounter(cadr, hmackey, input_tag);
  
  while(RPMC_ReadRPMCstatus(0)&0x01==0x01){
	// wait until RPMC operation done
  }  
  RPMC_ReadRPMCstatus(1);	// Get counter information
  
  message[0]=0x9B;
  message[1]=0x02;
  message[2]=cadr-1;
  message[3]=0x00;
  for(i=0;i<4;i++){
  message[i+4]=counter[i];
  }  
  
  hmacsha256(hmackey,32,message,8,signature);	// caculate signature by SHA256
  
  CS_LOW();
  for(i=0;i<8;i++){
  SPIin(message[i]);
  }
  for(i=0;i<32;i++){
  SPIin(signature[i]);
  }
  CS_HIGH();
  while(RPMC_ReadRPMCstatus(0)&0x01==0x01){
	// wait until RPMC operation done
  }  
  return RPMC_ReadRPMCstatus(0); 
}

/********************
Function: RPMC Challenge signature. Main security operation
Argument: 
	cadr: selected Counter address, from 1~4
	hmackey: 32 byte HMACKEY which is generated by RPMC_UpHMACkey()
	input_tag: 12 byte input Tag data, which can be time stamp, serial number or random number.
return: 
	Challlenge result. if signature match, return 0.
date: 2015/12/09
*********************/
unsigned char RPMC_Challenge(unsigned int cadr, unsigned char *hmackey,unsigned char *input_tag){
	unsigned char Verify_signature[32];	// signature for verification. should match signature[32]
	unsigned int i;
	RPMC_ReqCounter(cadr, hmackey, input_tag);
 	while(RPMC_ReadRPMCstatus(0)&0x01==0x01){
	// wait until RPMC operation done
 	}  
	RPMC_ReadRPMCstatus(1);	// Get counter information. In this stage, tag[12], counter[4], signature[32] is updated.
	// Comment: the message using for signature is tag[0:11]+count[0:3] data, you can also use memcpy to casecade these data
	/*
	memcpy(message, tag, 12);
	memcpy(message+12, counter, 4);
	*/	
	for(i = 0; i < 12; i++){
		message[i] = tag[i];	// message [0:11] = tag[0:11]
	}
	for(i = 0; i < 4; i++){
		message[12+i] = counter[i];	// message [12:15] = counter[0:3]
	}
	hmacsha256(hmackey,32,message,16,Verify_signature);	// Verification signature should as same as security output
	return memcmp(Verify_signature, signature, 32);		// Compare Verification signature (computed by controllor) and internal signature (return from security Flash by request counter operation)
}

/************************ (C) COPYRIGHT Winbond Electronics Corporation *****END OF FILE****/